/**
 * @file swei_uplink.c
 * @brief
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 *
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "include/port/swei_log.h"
#include "include/swei_common.h"
#include "include/port/swei_wrapper.h"
#include "include/swei_uplink.h"
#include "include/swei_login.h"
#include "include/swei_cache.h"
#include "include/swei_socket.h"
#include "include/swei_alarm.h"
#include "include/swei_status.h"
#include "include/swei_config.h"
#include "include/swei_package.h"
#include "include/swei_blinddata.h"
#include "utils/utils_timer.h"
#include "comm/co_heartbeat.h"
#include "misc/misc_system.h"
#include "include/swei_active.h"
#include "include/swei_config.h"
#include "include/task_service.h"

#define UPLINK_TIMER_INTERVAL (30 * 1000)

#define TYPE_STR(x, s) s
/**
 * @brief 上行消息类别，仅打印使用
 */
char *data_type_str[TYPE_MAX] = {
    TYPE_STR(TYPE_LOGIN, "LOGIN"),
    TYPE_STR(TYPE_HEARTBEAT, "HEARTBEAT"),
    TYPE_STR(TYPE_ACTIVE_REQ, "ACTIVE_REQ"),
    TYPE_STR(TYPE_LOC, "LOC"),
    TYPE_STR(TYPE_STATUS, "STATUS"),
    TYPE_STR(TYPE_ALARM, "ALM"),
    TYPE_STR(TYPE_CONFIG, "CFG"),
};


static void swei_srv_base_report_proc(uint8_t socket_ready);
bool base_report_is_busy(void);
/**
 * @brief 上行数据结构体
 */
typedef struct
{
    uint8_t wait_ack;       /*!< 消息发送应答 */
    uint8_t rpt_idle;       /*!< 报文发送空闲状态, true - 空闲 */

    utils_time_t loc_timer; /*!< LOCATION 数据发送定时器 */
    utils_time_t can_timer; /*!< CAN 发送定时器 */
    utils_time_t alm_timer; /*!< ALARM 发送定时器 */
    utils_time_t cfg_timer; /*!< CONFIG 发送定时器 */

    swei_datatype_t last_data; /*!< 上一条数据 */
} uplink_ctx_t;

uplink_ctx_t uplink_ctx = {0};

#define LOC_CHECK_INTERVAL      (1 * 1000)      /*!< location report interval: 5s */
#define STATUS_CHECK_INTERVAL   (1 * 1000)   /*!< can report interval: 5s */
#define ALARM_CHECK_INTERVAL    (1 * 1000)    /*!< alarm report interval: 2s */
#define CONFIG_CHECK_INTERVAL (120 * 1000) /*!< config report interval: 5s */

static void swei_srv_loc_proc(uint8_t online);
static void swei_srv_status_proc(uint8_t online);
static void swei_srv_alm_proc(uint8_t online);
static void swei_srv_cfg_proc(uint8_t online);
static void swei_srv_report_proc(uint8_t online);

uplink_record_t rec = {0};

static uint32_t next_time_rpt_send_time = 0;
static uint32_t curr_time_rpt_interval  = 0;

/**
 * @brief 
 */
void swei_uplink_init(void)
{
    uplink_ctx.wait_ack = false;

    utils_time_init(&uplink_ctx.loc_timer);
    utils_time_init(&uplink_ctx.can_timer);
    utils_time_init(&uplink_ctx.alm_timer);
    utils_time_init(&uplink_ctx.cfg_timer);
}

/**
 * @brief 设备在线状态获取
 * @return true - 在线, false - 不在线
 */
bool swei_online_status_get(void)
{

    // 2. distinguish the online status
    if (swei_login_is_ok() && swei_heartbeat_is_ok())
        return true;
    else
        return false;
}

/**
 * @brief 设备报文空闲状态获取
 * @return true - 在线, false - 不在线
 */
bool swei_uplink_data_idle_get(void)
{
    return uplink_ctx.rpt_idle;;
}

/**
 * @brief 设备报文空闲状态判断
 */
static void swei_uplink_data_idle_check(void)
{
    static uint32_t rpt_time = {0};
    static int32_t total_item = 0;
    int32_t cache_item = 0;
    int32_t flash_item = 0;

    if (0 == rpt_time)
        rpt_time = getsec();

    cache_item = swei_cache_item_get();
    flash_item = swei_blinddata_item_get();
    /* 判断报文数据是否发生变化 */
    if (total_item != (cache_item + flash_item)) {
        total_item = cache_item + flash_item;
        rpt_time = getsec();
        serviceSemaphoreTake();
        uplink_ctx.rpt_idle = false;
        serviceSemaphoreGive();
    }
    else {
        /* 60s没有产生/发送报文, 则设置当前报文状态空闲 */
        if (timeout_sec(rpt_time, 60)) {
            serviceSemaphoreTake();
            uplink_ctx.rpt_idle = true;
            serviceSemaphoreGive();
        }
    }

    /* 当前报文数据为空, 等待15s, 设置为报文为空闲状态 */
    if (0 == total_item && timeout_sec(rpt_time, 15)) {
        serviceSemaphoreTake();
        uplink_ctx.rpt_idle = true;
        serviceSemaphoreGive();
    }

    /* 当前报文发送最小间隔小于150s, 则不允许休眠 */
    if (150*1000 > curr_time_rpt_interval) {
        serviceSemaphoreTake();
        uplink_ctx.rpt_idle = true;
        serviceSemaphoreGive();
    }
}

typedef unsigned int (*next_send)(void);
typedef struct {
    bool                need_send;
    report_type_intv_t  type;
    next_send           send;
} next_send_manage_t;

next_send_manage_t send_manage_list[] = {
    {false,     REPORT_HEARTBEAT,      get_heartbeat_report_next_send},
    {false,     REPORT_GPS,            get_gps_report_next_send},
    {false,     REPORT_LBS,            get_lbs_report_next_send},
    {false,     REPORT_WIFI,           get_wifi_report_next_send},
    {false,     REPORT_RSRP_SIGNAL,    get_rsrp_report_next_send},
    {false,     REPORT_CAN_INFO_TYPE1, get_can_info_type1_report_next_send},
    {false,     REPORT_CAN_INFO_TYPE2, get_can_info_type2_report_next_send},
    {false,     REPORT_TBOX_BATT,      get_batt_report_next_send},
};

/**
 * @brief 位置报文下一次发送间隔获取, unit: ms
 * @return 
 */
uint32_t swei_uplink_data_next_stime_get(void)
{
    return next_time_rpt_send_time;
}

/**
 * @brief 位置报文下一次发送间隔判断
 */
static void swei_uplink_data_next_send_check(void)
{
    uint32_t min_interval = 0;
    uint32_t min_send_time = 0;
    uint32_t tmp_interval = 0;
    uint32_t tmp_send_time = 0;
    static uint32_t uptime = 0;

    /* 激活模式下, 获取各个定时报文下一次发送时间 */
    if (true == misc_get_active_state()) {
        for (int i = 0; i < ARRAY_COUNT(send_manage_list); i++) {
            tmp_interval = swei_config_rtp_intval_update(send_manage_list[i].type);
            /* 为0表示当前报文不使能, 所以不进行判断 */
            if (0 < tmp_interval) {
                send_manage_list[i].need_send = true;
                if (0 == min_interval || tmp_interval < min_interval)
                    min_interval = tmp_interval;
            }
            else {
                send_manage_list[i].need_send = false;
            }
        }

        for (int i = 0; i < ARRAY_COUNT(send_manage_list); i++) {
            /* 当前报文不需要发送 */
            if (!send_manage_list[i].need_send)
                continue;

            tmp_send_time = send_manage_list[i].send();
            /* 有报文需要发送, 且发送时间为0, 则直接返回0 */
            if (0 == tmp_send_time) {
                min_send_time = 0;
                break;
            }

            /* 更新最小发送时间 */
            if (0 == min_send_time || tmp_send_time < min_send_time)
                min_send_time = tmp_send_time;
        }

        next_time_rpt_send_time = min_send_time;
        curr_time_rpt_interval  = min_interval*1000;        /* 转化为ms */
    }
    else {
        next_time_rpt_send_time = 0xFFFFFFFF;               /* 非激活模式, 没有定时发送报文 */
        curr_time_rpt_interval  = 0xFFFFFFFF;
    }
    
    /* 定时打印下一次发送间隔 */
    if (0 == uptime || timeout_sec(uptime, 5)) {
        uptime = getsec();
        log_d("curr report min interval: %ums, next report send time: %ums\r\n", curr_time_rpt_interval, next_time_rpt_send_time);
    }
}

/**
 * @brief 
 */
void swei_uplink_process(void)
{
    uint8_t online = swei_online_status_get();
    uint8_t socket_ready = false;

    // 2. check if the socket is ready or not
    if (swei_socket_connect_ok()) {
        socket_ready = true;
    } else {
        socket_ready = false;
    }

    // packet message from message queue and push to cache buffer
    swei_srv_loc_proc(online);
    swei_srv_cfg_proc(online);
    swei_srv_status_proc(online);
    swei_srv_alm_proc(online);

    // deal with report data;
    swei_srv_base_report_proc(socket_ready);
    swei_srv_report_proc(online);
    swei_uplink_data_idle_check();
    swei_uplink_data_next_send_check();
}

/**
 * @brief 上行链路去初始化
 */
void swei_uplink_deinit(void)
{
}

/// @brief 定位信息采集流程; 1. 开机默认上报一次
/// @param online       - 在线状态 0 不在线 1 在线； 需要保存进入队列
static void swei_srv_loc_proc(uint8_t online)
{
    swei_datatype_t dt = {0};
    char data[512] = {0};

    // 1. check whether the loc timer timeout or not
    if (!utils_time_is_expired(&uplink_ctx.loc_timer))
    {
        return;
    }

    utils_time_countdown_ms(&uplink_ctx.loc_timer, LOC_CHECK_INTERVAL);

    // 2. packet buffer from loc message queue;
    dt.data_len = swei_packet_message(TYPE_LOC, (uint8_t *)data, sizeof(data));

    // 3. copy data content to dt;
    if (dt.data_len > 0)
    {
        dt.data_ptr = qlmalloc(dt.data_len);
        if (!dt.data_ptr)
        {
            log_e("malloc location info failed!\r\n");
            return;
        }
        
        memcpy(dt.data_ptr, data, dt.data_len);
        dt.data_type = TYPE_LOC;
    } else if (dt.data_len == 0) {
        log_d("there is not location message to send!\r\n");
        return;
    } else {
        log_e("there is a error with packet location message: %d!\r\n", dt.data_len);
        return;
    }

    // 4. push dt to cahce;
    if (0 != swei_cache_push(&dt, INSERT_BACK))
    {
        log_e("location info push to cache failed!\r\n");
        if (dt.data_ptr)
        {
            qlfree(dt.data_ptr);
        }
    }

    rec.loc_cnt++;
}

/// @brief 设备状态信息上报流程，关联文件swei_status;
/// @param online       - 在线状态 0 不在线 1 在线
static void swei_srv_status_proc(uint8_t online)
{
    swei_datatype_t dt = {0};
    char data[512] = {0};

    if (!online)
    {
        // can data fliter out when offline
        return;
    }

    if (utils_time_is_expired(&uplink_ctx.can_timer))
    {
        utils_time_countdown_ms(&uplink_ctx.can_timer, STATUS_CHECK_INTERVAL);

        // packet buffer;
        dt.data_len = swei_packet_message(TYPE_STATUS, (uint8_t *)data, sizeof(data));
        if (dt.data_len > 0)
        {
            dt.data_ptr = qlmalloc(dt.data_len);
            if (!dt.data_ptr)
            {
                log_e("malloc dt.dataptr failed!\r\n");
                return;
            }

            memcpy(dt.data_ptr, data, dt.data_len);
            dt.data_type = TYPE_STATUS;

            log_d("pack status packet success, len = %d\r\n", dt.data_len);
        }
        else
        {
            return;
        }

        // push packet to cache;
        if (0 != swei_cache_push(&dt, INSERT_BACK))
        {
            log_e("status info push to cache failed!\r\n");
            if (dt.data_ptr)
            {
                qlfree(dt.data_ptr);
            }
        }
    }

    rec.can_cnt++;
}

/// @brief 赛维平台告警处理流程 间隔ALARM_CHECK_INTERVAL时间检测告警队列，存在为上报告警则打包后放入cache
/// @param online       - 在线状态 0 不在线 1 在线
static void swei_srv_alm_proc(uint8_t online)
{
    swei_datatype_t dt = {0};
    swei_alarmtype_t node;
    char data[512] = {0};

    // pop from alarm queue, and push the alarm data packet into buffer
    if (utils_time_is_expired(&uplink_ctx.alm_timer))
    {
        utils_time_countdown_ms(&uplink_ctx.alm_timer, ALARM_CHECK_INTERVAL);

        // check whether alarm queue is not empty;
        if (0 == swei_alarm_peek(&node))
        {
            // packet buffer;
            dt.data_len = swei_packet_message(TYPE_ALARM, (uint8_t *)data, sizeof(data));
            if (dt.data_len > 0)
            {
                dt.data_ptr = qlmalloc(dt.data_len);
                if (!dt.data_ptr)
                {
                    log_e("get alarm info failed!\r\n");
                    return;
                }

                memcpy(dt.data_ptr, data, dt.data_len);
                dt.data_type = TYPE_ALARM;
            }
            else
            {
                log_e("get alarm info failed!\r\n");
                return;
            }

            // send packet to message queue
            if (0 != swei_cache_push(&dt, INSERT_BACK))
            {
                log_e("alarm info push to cache failed!\r\n");
                if (dt.data_ptr)
                {
                    qlfree(dt.data_ptr);
                }
            }
            else
            {
                rec.alarm_cnt++;
                swei_alarm_pop(&node);
                // co_aud_cmd(AUD_TYPE_ALARM); // 移动co_aud_cmd到告警触发时刻，保证告警及时响应，且无论是否入cache，都需要告警
            }
        }
    }
}

/// @brief report device config info (0 - normal; 1 - gsensor manager; 2 - gsensor driver;);
///        report one time when runnning up the system;
///        don`t report while the device is not actived;
/// @param online       - 在线状态 0 不在线 1 在线
static void swei_srv_cfg_proc(uint8_t online)
{
    swei_datatype_t dt          = {0};
    char data[512]              = {0};
    // static uint8_t _first_ready = false;

    if (!online) {
        // can data fliter out when offline
        return;
    }

    // at least upload one time
    if (swei_config_report_finish()) {
        // _first_ready = true;
        return;
    } else {
        // config report done already
        // _first_ready = false;
        utils_time_countdown_ms(&uplink_ctx.cfg_timer, 0);
    }

    // // 非激活状态下只上报一次，激活状态下，每次登录均触发上报
    // if (_first_ready) {
    //     log_w("device have not been actived, report config only one time!\r\n");
    //     return;
    // }

    if (utils_time_is_expired(&uplink_ctx.cfg_timer)) {
        utils_time_countdown_ms(&uplink_ctx.cfg_timer, CONFIG_CHECK_INTERVAL);

        // packet buffer;
        dt.data_len = swei_packet_message(TYPE_CONFIG, (uint8_t *)data, sizeof(data));
        if (dt.data_len > 0) {
            dt.data_ptr = qlmalloc(dt.data_len);
            if (!dt.data_ptr) {
                log_e("get config info failed!\r\n");
                return;
            }

            memcpy(dt.data_ptr, data, dt.data_len);
            dt.data_type = TYPE_CONFIG;
        } else if (0 == dt.data_len) {
            log_e("no more config info need send!\r\n");
            return;
        } else {
            log_e("get config info failed, dt.data_len = %d\r\n", dt.data_len);
            return;
        }

        // send packet to message queue
        if (0 != swei_cache_push(&dt, INSERT_BACK)) {
            log_e("alarm info push to cache failed!\r\n");
            if (dt.data_ptr) {
                qlfree(dt.data_ptr);
            }
        } else {
            log_i("push data into cache success, dt.data_id = %u, dt.data_type = %llu, dt.data_ptr = %p\r\n",
                                            dt.data_id, dt.data_type, dt.data_ptr);
            swei_config_report_trigger_next();
        } 
    }
}


/**
 * @brief 发送失败处理函数
 */
void _uplink_fail_proc(void)
{
    uplink_ctx.wait_ack = false;
    rec.fail_cnt++;
    rec.status = UPLINK_STATUS_IDLE;
    log_e("cache send failed, pop and check network!\r\n");
    /***
     * send fail, try load data to blind_data
     **/
    if (SUCC == swei_cache_pop(&uplink_ctx.last_data, true))
    {
        switch (uplink_ctx.last_data.data_type) {
            case TYPE_LOC:
            case TYPE_ALARM: {
                #warning "crash here, deal with it later."
                // swei_cache2blinddata(&uplink_ctx.last_data); // 
            } break;
            case TYPE_CONFIG:
            case TYPE_STATUS:
                // send failed, drop data;
                break;
        }
        
        if (uplink_ctx.last_data.data_ptr) {
            qlfree(uplink_ctx.last_data.data_ptr);
            uplink_ctx.last_data.data_ptr = NULL;
        }
    }

    memset(&uplink_ctx.last_data, 0, sizeof(uplink_ctx.last_data));
}

/**
 * @brief cache 数据上报流程， 数据出队，发送等待应答，应答则失败尝试重传，重传3次后丢弃
 * @param  online    在线状态 0 - 不在线 1 - 在线
 */
static void swei_srv_report_proc(uint8_t online)
{
    static utils_time_t uplink_timer = {0};
    static utils_time_t record_timer = {0};
    static uint8_t retry_send = 0;

    if (base_report_is_busy()) {
        return;
    }

    // 1. 应答处理逻辑
    if (uplink_ctx.wait_ack) {
        // 1.1 wait until the ack time[uplink_timer] timeout;
        if (!utils_time_is_expired(&uplink_timer)) {
            return;
        }

        utils_time_countdown_ms(&uplink_timer, UPLINK_TIMER_INTERVAL);
        
        // 1.2 record the fail time, while < 3, retry send; while >= 3, pop out and record the error log;
        retry_send++;
        log_w("cache send timeout, retry:%d\r\n", retry_send);
        if (retry_send >= 3) {
            retry_send = 0;
            _uplink_fail_proc();
        } else { /* retry time < 3; send repeat!*/
            if (!online) {
                log_w("offline while waitting ack for data!\r\n");
                if (retry_send >= 3) {
                    retry_send = 0;
                    _uplink_fail_proc();
                }
            } else {
                int32_t result = 0;

                rec.status = UPLINK_STATUS_RESENDING;
                log_d("retry send the last data from cache!\r\n");
                if ((result = swei_tcp_write((const void *)uplink_ctx.last_data.data_ptr, uplink_ctx.last_data.data_len)) > 0) {
                    log_i("retry send the last data success, result:%d!\r\n", result);
                } else {
                    log_e("retry send the last data failed, result:%d!\r\n", result);
                }
            }
        }

        return;
    }

    // 2. 设备在线情况处理, cache发送逻辑，peek后尝试发送，发送成功收到应答后出队，出队依赖于当前发送消息的id
    if (online) {
        if (uplink_ctx.last_data.data_ptr != NULL) {
            log_e("the memory of cache node did not free, data_ptr = %p!\r\n", 
                                uplink_ctx.last_data.data_ptr);
        }

        // 2.1 pick盲区缓存
        if (0 == swei_cache_peek(&uplink_ctx.last_data)) {
            int32_t result = 0;

            if (uplink_ctx.last_data.data_type >= TYPE_MAX) {
                log_e("data type error!\r\n");
                return;
            }
            
            log_d("peek cache success, data_type is %s\r\n", data_type_str[uplink_ctx.last_data.data_type]);

            if (!uplink_ctx.last_data.data_ptr || uplink_ctx.last_data.data_len == 0) {
                log_e("data_ptr or data_len error!\r\n");
                return;
            }

            // 3. 缓存出队，发送
            if ((result = swei_tcp_write((const void *)uplink_ctx.last_data.data_ptr, uplink_ctx.last_data.data_len)) > 0) {
                // send success, wait for ack
                uplink_ctx.wait_ack = true;
                retry_send          = 0;
                rec.status = UPLINK_STATUS_SENDING;

                utils_time_countdown_ms(&uplink_timer, UPLINK_TIMER_INTERVAL);
                log_i("cache send success, wait for ack!\r\n");
            } else {
                // send fail more than 3 times; drop out from the msgqueue;
                // if TYPE_LOC&TYPE_ALARM, will send by buffer queue;
                retry_send++;
                log_e("send cache data failed, result:%d, retry:%d\r\n", result, retry_send);
                if (retry_send >= 3) {
                    retry_send = 0;
                    _uplink_fail_proc();
                }
            }

            return;
        }

        // 2.2. 缓存空，尝试从flash加载缓存
        if (swei_cache_is_empty()) {
            // swei_cache_load();
        }
    } else { /* 3. 设备离线情况处理 */
        uplink_ctx.wait_ack = false;

        // 3.1. 缓存满，写入flash，情况缓存
        if (swei_cache_is_full()) {
            // swei_cache_flush();
        }

        // 3.2. 定期写入,间隔300s
        if (record_timer.time == 0) {
            utils_time_countdown_ms(&record_timer, 300 * 1000);
        }
        if (!swei_cache_is_empty() && utils_time_is_expired(&record_timer)) {
            utils_time_countdown_ms(&record_timer, 300 * 1000);

            // swei_cache_flush();
        }
    }
}

bool base_rpt_is_busy = false;
bool base_report_is_busy(void)
{
    return base_rpt_is_busy;
}

/**
 * @brief sys_cache  登录数据上报流程， 数据出队，发送等待应答，应答则直接丢弃
 * @param 
 */
static void swei_srv_base_report_proc(uint8_t socket_ready)
{
    swei_datatype_t data = {0};
    int8_t retry_send = 0;

    // 2. 设备在线情况处理, cache发送逻辑，peek后尝试发送，发送成功收到应答后出队，出队依赖于当前发送消息的id
    if (socket_ready) {
        // 2.1 pop from sys cache
        if (0 == swei_base_cache_pop(&data)) {
            int32_t result = 0;
            
            base_rpt_is_busy = true;

            if (data.data_type >= TYPE_LOC) {
                log_e("data type error!\r\n");
                if (data.data_ptr)
                    qlfree(data.data_ptr);
                
                base_rpt_is_busy = false;

                return;
            }
            
            log_d("pop base cache success, data_type is %s\r\n", data_type_str[data.data_type]);

            if (!data.data_ptr || data.data_len == 0) {
                log_e("data_ptr or data_len error!\r\n");
                if (data.data_ptr)
                    qlfree(data.data_ptr);

                base_rpt_is_busy = false;

                return;
            }

            // 3. 缓存出队，发送
            do {
                if ((result = swei_tcp_write((const void *)data.data_ptr, data.data_len)) > 0) {
                    log_i("base cache send success, wait for ack!\r\n");
                    break;
                } else {
                    retry_send++;
                    log_e("send base cache data failed, result:%d, retry:%d\r\n", result, retry_send);
                    if (retry_send >= 3) {
                        retry_send = 0;

                        log_e("send base cache data retry >= %d, result:%d\r\n", retry_send, result);
                        break;
                    }
                }
            } while(0);

            if (data.data_ptr)
                qlfree(data.data_ptr);
            
            base_rpt_is_busy = false;
        }
    } 
}



/// @brief 处理上行消息应答数据
/// @param ack_data_type 应答数据类型
/// @param serial_num    应答消息序列号
void swei_uplink_ack_proc(uint8_t ack_data_type, uint32_t serial_num)
{
    if (ack_data_type == uplink_ctx.last_data.data_type) {
        switch (ack_data_type) {
            
            case TYPE_LOC: {
                rec.loc_ack++;
            } break;

            case TYPE_ALARM: {
                rec.alarm_ack++;
            } break;

            case TYPE_STATUS: {
                rec.can_ack++;
            } break;

            case TYPE_CONFIG: {
                log_i("receieve config ack, serial_num:%d\r\n", serial_num);
                /* 收到应答，触发连续上报 */
                // swei_config_report_trigger_next();
                // utils_time_countdown_ms(&uplink_ctx.cfg_timer, 0);
            } break;

            default:
                // error data type
                break;
        }

        swei_cache_pop(&uplink_ctx.last_data, true);
        log_i("cache pop out, data type:%s, id = %d\r\n", data_type_str[uplink_ctx.last_data.data_type], uplink_ctx.last_data.data_id);
        if (uplink_ctx.last_data.data_ptr) {
            qlfree(uplink_ctx.last_data.data_ptr);
            uplink_ctx.last_data.data_ptr = NULL;
        }

        uplink_ctx.wait_ack = false;
    }
}

/**
 * @brief 查询记录句柄
 * @return uplink_record_t* 
 */
uplink_record_t *swei_uplink_get_rec(void)
{
    return &rec;
}

/**
 * @brief 清空所有的报文数据
 * @return
 */
void swei_uplink_data_clear(void)
{
    swei_cache_clear();
    swei_blinddata_clear();
}